package com.xfcy.blog.service.impl;

import com.xfcy.blog.common.constant.RedisConstant;
import com.xfcy.blog.common.enums.FriendLinkEnum;
import com.xfcy.blog.entity.FriendLink;
import com.xfcy.blog.entity.SystemConfig;
import com.xfcy.blog.service.EmailService;
import com.xfcy.blog.service.SystemConfigService;
import com.xfcy.blog.utils.ValidateCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.xml.crypto.Data;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

import static com.xfcy.blog.common.enums.FriendLinkEnum.UP;

/**
 * @author 晓风残月Lx
 * @date 2023/4/19 14:40
 */
@Slf4j
@Service("emailService")
public class EmailServiceImpl implements EmailService {

    @Resource
    private JavaMailSenderImpl javaMailSender;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Value("${spring.mail.username}")
    private String sendMailer;

    private  Map<Integer, Consumer<FriendLink>> map = new ConcurrentHashMap<>();

    @Resource
    private SystemConfigService systemConfigService;

    @PostConstruct
    public void init(){
        //初始化策略map
        map.put(FriendLinkEnum.UP.getCode(), friendLink ->  friendPassSendEmail(friendLink.getEmail()));
        map.put(FriendLinkEnum.DOWN.getCode(),friendLink ->  friendFailedSendEmail(friendLink.getEmail(),friendLink.getReason()));
    }

    /**
     * 友链不通过发送通知
     * @param email
     * @param reason
     */
    private void friendFailedSendEmail(String email, String reason) {
        String content = "<html>\n" +
                "<body>\n" +
                "    <p>您在"+"<a href=''>晓风残月Lx的博客</a>"+"站点申请友链加入审核不通过!!</span>\n" +
                "<p style='padding: 20px;'>感谢您的选择，本站将会竭尽维护好站点稳定，分享高质量的文章，欢迎相互交流互访。</p>" +
                "<p>可前往<a href=''>本站友链</a>查阅您的站点。</p></body>\n" +
                "</html>";
        try {
            send(email, content);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 友链通过发送通知
     * @param email
     */
    private void friendPassSendEmail(String email) {
        String content = "<html>\n" +
                "<body>\n" +
                "    <p>您在"+"<a href=''>晓风残月Lx的博客</a>"+"站点申请友链加入审核通过!!</span>\n" +
                "<p style='padding: 20px;'>感谢您的选择，本站将会竭尽维护好站点稳定，分享高质量的文章，欢迎相互交流互访。</p>" +
                "<p>可前往<a href=''>本站友链</a>查阅您的站点。</p></body>\n" +
                "</html>";
        try {
            send(email,content);
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    /**
     * 邮箱通知自己
     *
     * @param subject
     * @param content
     */
    @Override
    @Async("threadPoolTaskExecutor")
    public void emailNoticeMe(String subject, String content) {
        // 构建一个邮件对象
        SimpleMailMessage message = new SimpleMailMessage();
        // 设置邮件主题
        message.setSubject(subject);
        // 设置邮件发送者
        message.setFrom(Objects.requireNonNull(javaMailSender.getUsername()));
        // 设置收件人
        message.setTo(sendMailer);
        // 设置邮件的发送日期
        message.setSentDate(new Date());
        // 设置邮件的正文
        message.setText(content);
        // 发送邮件
        javaMailSender.send(message);
    }

    /**
     * 发送邮箱验证码
     *
     * @param email
     */
    @Override
    public void sendCode(String email) throws MessagingException {
        String emailCodeName = RedisConstant.EMAIL_CODE + email;
        Integer code = ValidateCodeUtils.generateValidateCode(6);

        if (redisTemplate.opsForValue().setIfAbsent(emailCodeName, code.toString(), RedisConstant.CAPTCHA_EXPIRATION_MINUTE, TimeUnit.MINUTES)) {
            send(email, emailHtml(code));
            log.info("邮箱验证码发送成功,邮箱:{},验证码:{}", email, code);
        } else {
            // EVAL "if redis.call('EXISTS',KEYS[1]) == 1 then redis.call('del',KEYS[1]) redis.call('SET', KEYS[1], ARGV[1]) redis.call('expire', KEYS[1], ARGV[2]) return 1 else return 0 end" 1 k1 v2 100
            String script = "if redis.call('EXISTS',KEYS[1]) == 1 then " +
                    "redis.call('del',KEYS[1]) " +
                    "redis.call('SET', KEYS[1], ARGV[1]) " +
                    "redis.call('expire', KEYS[1], ARGV[2]) " +
                    "return 1 " +
                    "else " +
                    "redis.call('SET', KEYS[1], ARGV[1]) " +
                    "redis.call('expire', KEYS[1], ARGV[2]) " +
                    "return 0 " +
                    "end ";
            log.info("验证码：{} ,键名:{},过期时间:{}", code.toString(), emailCodeName, String.valueOf(RedisConstant.CAPTCHA_EXPIRATION_SECOND));
            redisTemplate.execute(new DefaultRedisScript<Boolean>(script, Boolean.class), Arrays.asList(emailCodeName), code.toString(), String.valueOf(RedisConstant.CAPTCHA_EXPIRATION_SECOND));
            send(email, emailHtml(code));
            log.info("新的邮箱验证码发送成功,邮箱:{},新的验证码是:{}", email, code);
        }
    }

    /**
     * 审核友链通不通过发送通知
     * @param friendLink
     */
    @Override
    public void sendFriendEmail(FriendLink friendLink) {
        Consumer<FriendLink> friendLinkConsumer = map.get(friendLink.getStatus());
        if (friendLinkConsumer != null) {
            friendLinkConsumer.accept(friendLink);
        }
    }

    public void send(String email, String template) throws MessagingException {
        //创建一个MINE消息
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper mineHelper = new MimeMessageHelper(mimeMessage, true);
        // 设置邮件主题
        mineHelper.setSubject("晓风残月Lx的博客");
        // 设置邮件发送者
        mineHelper.setFrom(Objects.requireNonNull(javaMailSender.getUsername()));
        // 设置邮件接收者，可以有多个接收者，中间用逗号隔开
        mineHelper.setTo(email);
        // 设置邮件发送日期
        mineHelper.setSentDate(new Date());
        // 设置邮件的正文
        mineHelper.setText(template, true);
        // 发送邮件
        javaMailSender.send(mimeMessage);
    }


    /**
     * HTML版email 验证码
     *
     * @param code
     * @return
     */
    public String emailHtml(Integer code) {
        return "<!DOCTYPE html>\n" +
                "<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <title>邮箱验证码</title>\n" +
                "    <style>\n" +
                "        table {\n" +
                "            width: 700px;\n" +
                "            margin: 0 auto;\n" +
                "        }\n" +
                "        #top {\n" +
                "            width: 700px;\n" +
                "            border-bottom: 1px solid #ccc;\n" +
                "            margin: 0 auto 30px;\n" +
                "        }\n" +
                "        #top table {\n" +
                "            font: 12px Tahoma, Arial, 宋体;\n" +
                "            height: 40px;\n" +
                "        }\n" +
                "        #content {\n" +
                "            width: 680px;\n" +
                "            padding: 0 10px;\n" +
                "            margin: 0 auto;\n" +
                "        }\n" +
                "        #content_top {\n" +
                "            line-height: 1.5;\n" +
                "            font-size: 14px;\n" +
                "            margin-bottom: 25px;\n" +
                "            color: #4d4d4d;\n" +
                "        }\n" +
                "        #content_top strong {\n" +
                "            display: block;\n" +
                "            margin-bottom: 15px;\n" +
                "        }\n" +
                "        #content_top strong span {\n" +
                "            color: #f60;\n" +
                "            font-size: 16px;\n" +
                "        }\n" +
                "        #verificationCode {\n" +
                "            color: #f60;\n" +
                "            font-size: 24px;\n" +
                "        }\n" +
                "        #content_bottom {\n" +
                "            margin-bottom: 30px;\n" +
                "        }\n" +
                "        #content_bottom small {\n" +
                "            display: block;\n" +
                "            margin-bottom: 20px;\n" +
                "            font-size: 12px;\n" +
                "            color: #747474;\n" +
                "        }\n" +
                "        #bottom {\n" +
                "            width: 700px;\n" +
                "            margin: 0 auto;\n" +
                "        }\n" +
                "        #bottom div {\n" +
                "            padding: 10px 10px 0;\n" +
                "            border-top: 1px solid #ccc;\n" +
                "            color: #747474;\n" +
                "            margin-bottom: 20px;\n" +
                "            line-height: 1.3em;\n" +
                "            font-size: 12px;\n" +
                "        }\n" +
                "        #content_top strong span {\n" +
                "            font-size: 18px;\n" +
                "            color: #FE4F70;\n" +
                "        }\n" +
                "        #sign {\n" +
                "            text-align: right;\n" +
                "            font-size: 18px;\n" +
                "            color: #FE4F70;\n" +
                "            font-weight: bold;\n" +
                "        }\n" +
                "        #verificationCode {\n" +
                "            height: 100px;\n" +
                "            width: 680px;\n" +
                "            text-align: center;\n" +
                "            margin: 30px 0;\n" +
                "        }\n" +
                "        #verificationCode div {\n" +
                "            height: 100px;\n" +
                "            width: 680px;\n" +
                "        }\n" +
                "        .button {\n" +
                "            color: #FE4F70;\n" +
                "            margin-left: 10px;\n" +
                "            height: 80px;\n" +
                "            width: 80px;\n" +
                "            resize: none;\n" +
                "            font-size: 42px;\n" +
                "            border: none;\n" +
                "            outline: none;\n" +
                "            padding: 10px 15px;\n" +
                "            background: #ededed;\n" +
                "            text-align: center;\n" +
                "            border-radius: 17px;\n" +
                "            box-shadow: 6px 6px 12px #cccccc,\n" +
                "            -6px -6px 12px #ffffff;\n" +
                "        }\n" +
                "        .button:hover {\n" +
                "            box-shadow: inset 6px 6px 4px #d1d1d1,\n" +
                "            inset -6px -6px 4px #ffffff;\n" +
                "        }\n" +
                "    </style>\n" +
                "</head>\n" +
                "<body>\n" +
                "<table>\n" +
                "    <tbody>\n" +
                "    <tr>\n" +
                "        <td>\n" +
                "            <div id=\"top\">\n" +
                "                <table>\n" +
                "                    <tbody><tr><td></td></tr></tbody>\n" +
                "                </table>\n" +
                "            </div>\n" +
                "            <div id=\"content\">\n" +
                "                <div id=\"content_top\">\n" +
                "                    <strong>尊敬的用户：您好！</strong>\n" +
                "                    <strong>\n" +
                "                        您正在进行<span>注册账号</span>操作，请在验证码中输入以下验证码完成操作：\n" +
                "                    </strong>\n" +
                "                    <div id=\"verificationCode\">\n" +
                "                        <p>" + code + "<p>\n" +
                "                    </div>\n" +
                "                </div>\n" +
                "                <div id=\"content_bottom\">\n" +
                "                    <small>\n" +
                "                        注意：此操作可能会修改您的密码、登录邮箱或绑定手机。如非本人操作，请及时登录并修改密码以保证帐户安全\n" +
                "                        <br>（工作人员不会向你索取此验证码，请勿泄漏！)\n" +
                "                    </small>\n" +
                "                </div>\n" +
                "            </div>\n" +
                "            <div id=\"bottom\">\n" +
                "                <div>\n" +
                "                    <p>此为系统邮件，请勿回复<br>\n" +
                "                        请保管好您的邮箱，避免账号被他人盗用\n" +
                "                    </p>\n" +
                "                    <p id=\"sign\">——晓风残月Lx</p>\n" +
                "                </div>\n" +
                "            </div>\n" +
                "        </td>\n" +
                "    </tr>\n" +
                "    </tbody>\n" +
                "</table>\n" +
                "</body>\n";
    }

}
